# widgets/bms_config_widget.py
import os
import json
import pickle
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QComboBox,
                             QGroupBox, QGridLayout, QMessageBox, QInputDialog, QFileDialog)
from PySide6.QtGui import QFont, QIcon
from PySide6.QtCore import Signal
from components.bms_table import BMSTable
from utils.column_name_matcher import ColumnNameMatcher
from utils.smart_column_finder import AINameMatcher

class BmsConfigWidget(QWidget):
    """3. BMS列配置Tab：负责BMS信号列映射、AI/正则匹配、运算设置、配置保存"""
    next_clicked = Signal()  # 下一步
    prev_clicked = Signal()  # 上一步

    def __init__(self, app_data, parent=None):
        super().__init__(parent)
        self.CONFIG_DIR = app_data.CONFIG_DIR  # BMS配置文件目录
        self.OUTPUT_FILE = app_data.OUTPUT_FILE  # 输出指标配置文件
        self.device_profiles = self.load_device_profiles()
        self.init_ui()


    def init_ui(self):
        """搭建BMS配置UI"""
        layout = QVBoxLayout(self)

        # 1. 标题区域
        title = QLabel("BMS列配置")
        title.setFont(QFont("Arial", 16, QFont.Bold))
        layout.addWidget(title)

        # 配置说明
        desc = QLabel("配置BMS信号对应的列名，点击「一键匹配」可自动识别列名")
        layout.addWidget(desc)

        # 2. BMS列映射区域
        bms_group = QGroupBox("BMS列映射")
        bms_layout = QGridLayout(bms_group)
        # 匹配按钮（正则+AI）
        bms_layout.addWidget(QLabel("自动匹配："), 0, 0)
        self.re_btn = QPushButton("一键正则匹配")
        self.re_btn.clicked.connect(self.re_infer_columns)
        bms_layout.addWidget(self.re_btn, 0, 1)
        self.ai_btn = QPushButton("一键AI推断")
        self.ai_btn.clicked.connect(self.ai_infer_columns)
        bms_layout.addWidget(self.ai_btn, 0, 2)
        layout.addWidget(bms_group)

        # 3. BMS配置表格（自定义组件）
        self.bms_table = BMSTable(self)

        layout.addWidget(self.bms_table)

        # 5. 配置管理（加载/保存/导出）
        config_manage_group = QGroupBox("配置管理")
        config_manage_layout = QHBoxLayout(config_manage_group)
        selection_layout = QHBoxLayout()
        selection_layout.setSpacing(10)
        selection_layout.addWidget(QLabel("选择设备型号和软件版本:"))
        self.device_combo = QComboBox()
        self.device_combo.addItems(self.device_profiles)
        self.device_combo.currentIndexChanged.connect(self.update_config_fields)
        self.device_combo.setMinimumWidth(200)
        selection_layout.addWidget(self.device_combo)
        config_manage_layout.addLayout(selection_layout)
        self.save_btn = QPushButton("保存配置")
        self.save_btn.clicked.connect(self.save_bms_config)
        self.export_btn = QPushButton("导出配置")
        self.export_btn.clicked.connect(self.export_bms_config)

        config_manage_layout.addWidget(self.save_btn)
        config_manage_layout.addWidget(self.export_btn)
        layout.addWidget(config_manage_group)

        # 6. 底部按钮（上一步/下一步）
        btn_layout = QHBoxLayout()
        self.prev_btn = QPushButton("上一步：设备配置")
        self.prev_btn.setIcon(QIcon.fromTheme("go-previous"))
        self.prev_btn.clicked.connect(self.on_prev_clicked)
        self.next_btn = QPushButton("下一步：工步配置")
        self.next_btn.setIcon(QIcon.fromTheme("go-next"))
        self.next_btn.clicked.connect(self.on_next_clicked)
        btn_layout.addWidget(self.prev_btn)
        btn_layout.addStretch()
        btn_layout.addWidget(self.next_btn)
        layout.addLayout(btn_layout)
        self.update_config_fields()

    def get_bms_config(self):
        """获取当前BMS配置（信号→列名）"""
        bms_config = self.bms_table.get_all_configs()
        return bms_config

    def update_config_fields(self):
        """设备选项发生变化时更新配置字段"""
        device_index = self.device_combo.currentIndex()
        if 0 <= device_index < len(self.device_profiles):
            profile = self.device_profiles[device_index]
            file_path = os.path.join(self.CONFIG_DIR, profile + ".json")
            self.load_bms_config(file_path)

    def re_infer_columns(self):
        """正则匹配BMS列名"""
        # 获取表格中的BMS信号名
        signals = self.bms_table.get_csv_columns()
        if not signals:
            QMessageBox.warning(self, "无信号", "请先确保BMS信号列表已加载")
            return
        # 禁用按钮，防止重复点击
        self.re_btn.setEnabled(False)
        self.re_btn.setText("匹配中...")
        # 启动线程执行正则匹配（避免阻塞UI）
        self.re_matcher = ColumnNameMatcher(self)
        self.re_matcher.set_from_columns(signals)
        self.re_matcher.result.connect(self.apply_match_result)
        self.re_matcher.finished.connect(lambda: self.re_btn.setText("一键正则匹配"))
        self.re_matcher.start()
        self.re_btn.setEnabled(True)

    def ai_infer_columns(self):
        """AI推断BMS列名"""
        signals = self.bms_table.get_csv_columns()
        if not signals:
            QMessageBox.warning(self, "无信号", "请先确保BMS信号列表已加载")
            return
        self.ai_btn.setEnabled(False)
        self.ai_btn.setText("推断中...")
        # 启动AI匹配线程
        self.ai_matcher = AINameMatcher(self)
        self.ai_matcher.set_from_columns(signals)
        self.ai_matcher.result.connect(self.apply_match_result)
        self.ai_matcher.finished.connect(lambda: self.ai_btn.setText("一键AI推断"))
        self.ai_matcher.start()
        self.ai_btn.setEnabled(True)

    def apply_match_result(self, data):
        """应用匹配结果到表格"""
        matched_columns = pickle.loads(data)
        row_count = self.bms_table.rowCount()
        for row in range(row_count):
            combobox = self.bms_table.cellWidget(row, 1)
            combobox.setCurrentText(matched_columns[row])

    def load_device_profiles(self) -> list:
        """加载设备配置"""
        config_dir = self.CONFIG_DIR
        return [item[:-5] for item in os.listdir(config_dir) if item.endswith(".json")]

    def load_bms_config(self, file_path: str):
        """加载BMS配置文件（JSON）"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                config = json.load(f)
                self.bms_table.init_from_config(config)
        except Exception as e:
            QMessageBox.critical(self, "加载失败", f"配置文件读取错误：{str(e)}")

    def save_bms_config(self):
        """保存BMS配置到文件（指定名称）"""
        if not os.path.exists(self.CONFIG_DIR):
            os.makedirs(self.CONFIG_DIR)  # 目录不存在则创建
        config_name, ok = QInputDialog.getText(self, "保存配置", "请输入配置名称：")
        if not ok or not config_name.strip():
            return
        file_path = os.path.join(self.CONFIG_DIR, f"{config_name}.json")
        try:
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(self.get_bms_config(), f, ensure_ascii=False, indent=4)
            QMessageBox.information(self, "保存成功", f"配置已保存至：{file_path}")
        except Exception as e:
            QMessageBox.critical(self, "保存失败", f"配置文件写入错误：{str(e)}")

    def export_bms_config(self):
        """导出当前BMS配置（自定义路径）"""
        from datetime import datetime
        default_name = f"BMS配置_{datetime.now().strftime('%Y%m%d')}.json"
        file_path, _ = QFileDialog.getSaveFileName(
            self, "导出BMS配置", default_name, "JSON文件 (*.json)"
        )
        if not file_path:
            return
        try:
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(self.get_bms_config(), f, ensure_ascii=False, indent=4)
            QMessageBox.information(self, "导出成功", f"配置已导出至：{file_path}")
        except Exception as e:
            QMessageBox.critical(self, "导出失败", f"配置文件写入错误：{str(e)}")

    def update_combobox_items(self, columns):
        """更新表格中所有下拉框的选项（列名）"""
        # 遍历BMS配置表格的每一行，更新第二列（下拉框）的选项
        row_count = self.bms_table.rowCount()
        for row in range(row_count):
            # 获取当前行的下拉框组件
            combobox = self.bms_table.cellWidget(row, 1)
            current_text = combobox.currentText()
            if combobox:
                combobox.clear()  # 清空现有选项
                combobox.addItems(columns)  # 添加新列名
                combobox.setCurrentText(current_text)

    def on_prev_clicked(self):
        """上一步按钮点击事件"""
        # 由主窗口处理切换Tab
        self.prev_clicked.emit()

    def on_next_clicked(self):
        """下一步按钮点击事件"""
        # 由主窗口处理切换Tab
        self.next_clicked.emit()
